//  Copyright (c) 2009 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
using DNA.Mvc.jQuery;
using DNA.Utility;
using DNA.IO.Compress;
using System.Web.Security;
using DNA.Mvc.UI;
using DNA.Mvc.Exporting;

namespace DNA.Mvc.Controllers
{
    //[HandlePartialError]
    public partial class WidgetController : Controller
    {
        private WebSiteContext _context;
        public WidgetController(WebSiteContext context) { _context = context; }

        /// <summary>
        /// Add new widget instance to the specified widget zone.
        /// </summary>
        /// <param name="wid">specified WidgetDescriptor ID</param>
        /// <param name="url">the target page url</param>
        /// <param name="zoneID">the specified widget zone id</param>
        /// <param name="pos">the position of the widget in wiget zone</param>
        /// <returns></returns>
        [HttpPost]
        [SecurityAction("Widgets", "Add widget to page", "Allows user add a new widget instance to the exists page.",
            TitleResName = "SA_AddWidget",
            DescResName = "SA_AddWidgetDesc",
            PermssionSetResName = "SA_Widgets"
            )]
        public ActionResult AddTo(int wid, Uri url, string zoneID, int pos)
        {
            var descriptor = _context.DataContext.WidgetDescriptors.Find(wid);

            if (descriptor == null)
                throw new HttpException("The widget not found");

            var w = _AddWidgetCore(url, zoneID, pos, descriptor);

            _ResolveUrls(w);

            object _widget = ToJson(w);

            return Json(_widget, JsonRequestBehavior.AllowGet);
        }

        private static dynamic ToJson(WidgetInstance w)
        {
            return new
            {
                ID = w.ID.ToString(),
                IsClosable = w.IsClosable,
                IsDeletable = w.IsDeletable,
                IsExpanded = w.IsExpanded,
                CssText = w.CssText,
                HeaderCssText = w.HeaderCssText,
                BodyCssText = w.BodyCssText,
                Pos = w.Pos,
                ShowHeader = w.ShowHeader,
                ShowBorder = w.ShowBorder,
                Title = w.Title,
                TitleLinkUrl = w.TitleLinkUrl,
                IconUrl = w.IconUrl,
                ContentUrl = w.ContentUrl,
                ZoneID = w.ZoneID
            };
        }

        private void _ResolveUrls(WidgetInstance widgetInstance)
        {
            string website = "";

            if (RouteData.Values.ContainsKey("website"))
                website = RouteData.Values["website"] as string;

            if (!string.IsNullOrEmpty(widgetInstance.IconUrl))
                widgetInstance.IconUrl = Url.Content(widgetInstance.IconUrl);

            if (!string.IsNullOrEmpty(widgetInstance.TitleLinkUrl))
                widgetInstance.TitleLinkUrl = Url.Content(widgetInstance.TitleLinkUrl);

            _ResolveWidgetContentUrl(widgetInstance, website);
        }

        private void _ResolveWidgetContentUrl(WidgetInstance widgetInstance, string website)
        {
            //Parse widget url in assembly
            if (!string.IsNullOrEmpty(widgetInstance.Controller) && !string.IsNullOrEmpty(widgetInstance.Action))
                widgetInstance.ContentUrl = !string.IsNullOrEmpty(website) ? Url.Action(widgetInstance.Action, widgetInstance.Controller, new { Area = string.IsNullOrEmpty(widgetInstance.Area) ? "" : widgetInstance.Area, website = website, id = 0 }) : Url.Action(widgetInstance.Action, widgetInstance.Controller, new { Area = string.IsNullOrEmpty(widgetInstance.Area) ? "" : widgetInstance.Area });
            else
                widgetInstance.ContentUrl = !string.IsNullOrEmpty(website) ? Url.Action("Generic", "Widget", new { Area = "", website = website }) : Url.Action("Generic", "Widget", new { Area = "" });
        }

        private WidgetInstance _AddWidgetCore(Uri url, string zoneID, int pos, WidgetDescriptor descriptor)
        {
            var page = _context.FindWebPage(url);

            string vPath = "";
            if (page == null)
            {
                var routeData = _context.FindRoute(url);
                if (routeData != null)
                {
                    page = _context.FindWebPage(url, routeData);
                }
            }
            vPath = page.Path;
            var widgetInstance = _context.DataContext.Widgets.AddWidget(Guid.NewGuid(), descriptor, vPath, zoneID, pos);
            _context.DataContext.SaveChanges();
            return widgetInstance;
        }

        [Authorize]
        public ActionResult LoadData(Uri url)
        {
            WebPage page = null;

            //The Route is diff
            if (Request.IsAjaxRequest())
            {
                var routeData = _context.FindRoute(url);
                if (routeData != null)
                {
                    page = _context.FindWebPage(url, routeData);
                }
            }
            else
                page = _context.FindWebPage(url);

            if (page == null)
                return Content("");

            //Auth
            if (page.Web.IsRoot)
            {
                if (!page.Owner.Equals(User.Identity.Name) && !_context.IsAuthorized(this, "Explorer"))
                    return Content("");
            }
            else
            {
                if (!page.Owner.Equals(User.Identity.Name))
                    return Content("");
            }

            string website = "";
            if (RouteData.Values.ContainsKey("website"))
                website = RouteData.Values["website"] as string;

            var _widgets = from w in page.Widgets
                           select new
                           {
                               ID = w.ID.ToString(),
                               IsClosable = w.IsClosable,
                               IsDeletable = w.IsDeletable,
                               IsExpanded = w.IsExpanded,
                               CssText = w.CssText,
                               HeaderCssText = w.HeaderCssText,
                               BodyCssText = w.BodyCssText,
                               Pos = w.Pos,
                               ShowHeader = w.ShowHeader,
                               ShowBorder = w.ShowBorder,
                               Title = w.Title,
                               TitleLinkUrl = !string.IsNullOrEmpty(w.TitleLinkUrl) ? Url.Content(w.TitleLinkUrl) : "",
                               IconUrl = !string.IsNullOrEmpty(w.IconUrl) ? Url.Content(w.IconUrl) : "",
                               ContentUrl = (!string.IsNullOrEmpty(w.Controller) && !string.IsNullOrEmpty(w.Action)) ? (w.ContentUrl = !string.IsNullOrEmpty(website) ? Url.Action(w.Action, w.Controller, new { Area = string.IsNullOrEmpty(w.Area) ? "" : w.Area, website = website, id = 0 }) : Url.Action(w.Action, w.Controller, new { Area = string.IsNullOrEmpty(w.Area) ? "" : w.Area })) : (!string.IsNullOrEmpty(website) ? Url.Action("Generic", "Widget", new { Area = "", website = website }) : Url.Action("Generic", "Widget", new { Area = "" })),
                               ZoneID = w.ZoneID
                           };

            if (_widgets == null)
                return Content("");

            List<DynamicGroupResult> widgets = null;

            widgets = _widgets.OrderBy(w => w.Pos).GroupByMany(w => w.ZoneID).ToList();

            if (widgets.Count() == 0)
                return Content("");

            return Json(widgets, JsonRequestBehavior.AllowGet);
        }

        /// <summary>
        /// Move the widget to anthor widget zone or new position.
        /// </summary>
        /// <param name="id">The specified widget id.</param>
        /// <param name="zoneID">The target widget zone id.</param>
        /// <param name="position">The new  position of the widget</param>
        [HttpPost]
        [SecurityAction("Widgets", "Drag and drop widgets", "Allows user drag and drop the widgets on the page.",
            ThrowOnDeny = true,
            TitleResName = "SA_MoveWidget",
            DescResName = "SA_MoveWidgetDesc",
            PermssionSetResName = "SA_Widgets"
            )]
        public void MoveTo(Guid id, string zoneID, int position)
        {
            if (id.Equals(Guid.Empty)) throw new ArgumentNullException("id");
            if (string.IsNullOrEmpty(zoneID)) throw new ArgumentNullException("zoneID");
            if (position < 0) throw new ArgumentOutOfRangeException("position");

            using (_context)
            {
                _context.DataContext.Widgets.MoveTo(id, zoneID, position);
                _context.DataContext.SaveChanges(false);
            }
        }

        /// <summary>
        /// Delete the widget by specified id. 
        /// </summary>
        /// <param name="id">The id of the widget.</param>
        [HttpPost]
        [SecurityAction("Widgets", "Delete widget", "Allows users delete the existing widgets.",
            ThrowOnDeny = true,
            TitleResName = "SA_DeleteWidget",
            DescResName = "SA_DeleteWidgetDesc",
            PermssionSetResName = "SA_Widgets"
            )]
        public void Delete(Guid id)
        {
            if (id.Equals(Guid.Empty)) throw new ArgumentNullException("id");
            using (_context)
            {
                var widget = _context.DataContext.Widgets.Find(id);
                _context.DataContext.Widgets.Delete(widget);
                _context.DataContext.SaveChanges();
            }
        }

        /// <summary>
        /// Apply the common settings of the widget.
        /// </summary>
        /// <param name="id">The specified widget id</param>
        [HttpPost]
        [SecurityAction("Widgets", "Apply widget settings", "Allows users can apply the common widget settings changes",
            ThrowOnDeny = true,
            TitleResName = "SA_ApplyWidgetSettings",
            DescResName = "SA_ApplyWidgetSettingsDesc",
            PermssionSetResName = "SA_Widgets"
            )]
        public void Apply(Guid id)
        {
            if (id.Equals(Guid.Empty)) throw new ArgumentNullException("id");

            using (_context)
            {
                var widget = _context.DataContext.Widgets.Find(id);

                if (TryUpdateModel<WidgetInstance>(widget, new string[] {
                "ShowBorder","ShowHeader","IsClosable",
                "Title","TitleLinkUrl","IconUrl"}))
                {
                    _context.DataContext.Widgets.Update(widget);
                    _context.DataContext.SaveChanges(false);
                }
            }
        }

        [HttpPost]
        [SecurityAction("Widgets", "Toggle widget state", "Allows users collapse or expand widgets.",
            ThrowOnDeny = true,
            TitleResName = "SA_ToggleWidget",
            DescResName = "SA_ToggleWidgetDesc",
            PermssionSetResName = "SA_Widgets"
            )]
        public void Toggle(Guid id)
        {
            if (id != Guid.Empty)
            {
                using (_context)
                {
                    var widget = _context.DataContext.Widgets.Find(id);
                    widget.IsExpanded = !widget.IsExpanded;
                    _context.DataContext.Update(widget);
                    _context.DataContext.SaveChanges(false);
                }
            }
        }

        [SecurityAction("Widgets", "Design page", "Allows users could switch the page design mode.",
            TitleResName = "SA_DesignPage",
            DescResName = "SA_DesignPageDesc",
            PermssionSetResName = "SA_Widgets"
            )]
        public ActionResult Explorer()
        {
            string root = HttpContext.Server.MapPath("~/content/widgets/");
            return PartialView(GetPathNodes(root, root));
        }

        /// <summary>
        /// List the installed widget paths (Only avalidable in DNA2)
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        [Authorize, Pagable]
        public ActionResult List(string path, QueryParams query)
        {
            //var descriptors = Service.GetWidgetDescriptors(path);
            var descriptors = _context.DataContext.WidgetDescriptors.WithInPath(path);
            string website = "";

            if (RouteData.Values.ContainsKey("website"))
                website = RouteData.Values["website"] as string;

            var results = descriptors.OrderBy(m => m.Title)
                .Skip(query.GetSkipRecordCount(true))
                .Take(query.Size)
                .ToList();

            foreach (var d in results)
            {
                try
                {
                    if (!string.IsNullOrEmpty(d.ImageUrl))
                        d.ImageUrl = Url.Content(d.ImageUrl);
                    if (!string.IsNullOrEmpty(d.IconUrl))
                        d.IconUrl = Url.Content(d.IconUrl);

                    if (!string.IsNullOrEmpty(d.Controller) && !string.IsNullOrEmpty(d.Action))
                        d.ContentUrl = !string.IsNullOrEmpty(website) ? Url.Action(d.Action, d.ControllerShortName, new { Area = string.IsNullOrEmpty(d.Area) ? "" : d.Area, website = website, id = 0 }) : Url.Action(d.Action, d.ControllerShortName, new { Area = string.IsNullOrEmpty(d.Area) ? "" : d.Area });
                    else
                        d.ContentUrl = !string.IsNullOrEmpty(website) ? Url.Action("Generic", "Widget", new { Area = "", website = website }) : Url.Action("Generic", "Widget", new { Area = "" });
                }
                catch (Exception e)
                {
                    continue;
                }
            }

            return View(new ModelWrapper<WidgetDescriptor>()
            {
                Total = descriptors.Count(),
                Model = results
            });
        }

        [Authorize]
        public JsonResult LoadDescriptor(string wid)
        {

            var id = Server.UrlDecode(wid);
            string website = _context.Web.Name;
            var descriptor = _context.DataContext.WidgetDescriptors.Find(id);

            if (descriptor == null)
            {
                var tmpl = _context.DataContext.WidgetTemplates.Find(id);
                descriptor = _context.DataContext.WidgetDescriptors.Create(tmpl, id);
            }

            if (!string.IsNullOrEmpty(descriptor.ImageUrl))
                descriptor.ImageUrl = Url.Content(descriptor.ImageUrl);
            if (!string.IsNullOrEmpty(descriptor.IconUrl))
                descriptor.IconUrl = Url.Content(descriptor.IconUrl);

            if (!string.IsNullOrEmpty(descriptor.Controller) && !string.IsNullOrEmpty(descriptor.Action))
                descriptor.ContentUrl = !string.IsNullOrEmpty(website) ? Url.Action(descriptor.Action, descriptor.ControllerShortName, new { Area = string.IsNullOrEmpty(descriptor.Area) ? "" : descriptor.Area, website = website, id = 0 }) : Url.Action(descriptor.Action, descriptor.ControllerShortName, new { Area = string.IsNullOrEmpty(descriptor.Area) ? "" : descriptor.Area });
            else
                descriptor.ContentUrl = !string.IsNullOrEmpty(website) ? Url.Action("Generic", "Widget", new { Area = "", website = website }) : Url.Action("Generic", "Widget", new { Area = "" });

            var _widget = new
            {
                ID = descriptor.ID.ToString(),
                IsClosable = descriptor.IsClosable,
                IsDeletable = descriptor.IsDeletable,
                IsExpanded = true,
                CssText = "",
                HeaderCssText = "",
                BodyCssText = "",
                Pos = 0,
                ShowHeader = descriptor.ShowHeader,
                ShowBorder = descriptor.ShowBorder,
                Title = descriptor.Title,
                TitleLinkUrl = descriptor.TitleLinkUrl,
                IconUrl = descriptor.IconUrl,
                ContentUrl = descriptor.ContentUrl
            };

            return Json(_widget, JsonRequestBehavior.AllowGet);
        }

        private List<NavigatableNode> GetPathNodes(string path, string root)
        {
            var dirInfo = new DirectoryInfo(path);
            var dirs = dirInfo.GetDirectories();

            var dirNodes = new List<NavigatableNode>();
            foreach (var dir in dirs)
            {
                var files = dir.GetFiles("config.xml");
                if (files.Length > 0)
                    continue;

                dirNodes.Add(new NavigatableNode()
                {
                    Text = dir.Name + " (" + dir.GetDirectories().Length.ToString() + ")",
                    Value = dir.Name,// Url.Action("GetPaths", "Host", new { name = dir.FullName.Replace(root, "") }),
                    ImageUrl = Url.Content("~/content/images/icon_cat_16.gif"),
                    NavigateUrl = "javascript:void(0);"
                });
            }
            return dirNodes;
        }

        /// <summary>
        /// Get the specified WidgetDescriptor install information.
        /// </summary>
        /// <param name="id">The specified widget descriptor id.</param>
        /// <returns></returns>
        [Authorize]
        public ActionResult Info(int id)
        {
            //ViewData.Model = Service.GetWidgetDescriptor(id);
            return PartialView(_context.DataContext.WidgetDescriptors.Find(id));
        }

        /// <summary>
        /// Export the specified widget settings to the file.
        /// </summary>
        /// <param name="wid">The specified widgetinstance id</param>
        /// <returns></returns>
        [SecurityAction("Widgets", "Export user preferences",
            "Allows users can export the user preferences data and download it.",
            TitleResName = "SA_ExportWidgetData",
            DescResName = "SA_ExportWidgetDataDesc",
            PermssionSetResName = "SA_Widgets"
            )]
        public FileResult Export(Guid wid)
        {
            var widget = _context.DataContext.Widgets.Find(wid);
            if (widget == null)
                throw new Exception("Widget not found");
            var stream = new MemoryStream();
            var writer = new StreamWriter(stream);
            writer.Write(widget.ToXml());
            writer.Flush();
            stream.Position = 0;
            return File(stream, "text/xml", TextUtility.Slug(widget.Title + DateTime.Now.ToString("yy-MM-dd")) + ".dat");
        }

        /// <summary>
        /// Add a new widget instance from the import data file
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [SecurityAction("Widgets", "Import user preferences", "Allows users can upload the widget user preferences data file and import to the exists page.",
            ThrowOnDeny = true,
            TitleResName = "SA_ImportWidgetData",
            DescResName = "SA_ImportWidgetDataDesc",
            PermssionSetResName = "SA_Widgets"
            )]
        public ActionResult Import(Uri url, string zoneID, int pos)
        {
            var postedFile = Request.Files["importedFile"];
            var page = _context.FindWebPage(url);

            if (page == null)
            {
                var routeData = _context.FindRoute(url);
                if (routeData != null)
                {
                    page = _context.FindWebPage(url, routeData);
                }
            }

            var _tmpl = TemplateHelper.LoadWidgetTemplate(postedFile.InputStream);
            var widgetInstance = _context.DataContext.Widgets.AddWidget(Guid.NewGuid(), _tmpl, page.Path, zoneID, pos);
            widgetInstance.ZoneID = zoneID;
            widgetInstance.Pos = pos;
            _context.DataContext.SaveChanges(false);
            this._ResolveUrls(widgetInstance);

            //The IE rubbish could not support Json method!
            //return Json(ToJson(widgetInstance), JsonRequestBehavior.AllowGet);
            return Content(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ToJson(widgetInstance)));
        }

        [SiteControlPanel(ResKey = "RES_WIDGETS", Order = 1, Group = "Widgets", GroupResKey = "RES_WIDGETS", ShowInTopSiteOnly = true)]
        [SecurityAction("Widgets", "Widget manager", "Allows uses could installed,upload,remove and edit widgets by using WidgetManager",
    ThrowOnDeny = true,
    TitleResName = "SA_WidgetMan",
    DescResName = "SA_WidgetManDesc",
    PermssionSetResName = "SA_Widgets"
    )]
        [Pagable]
        public ActionResult WidgetManager(QueryParams query, string category = "Shared")
        {
            ViewBag.Category = category;

            #region Check conflict
            var tmpls = _context.DataContext.WidgetTemplates.All();
            var conflictCount = 0;
            foreach (var tmpl in tmpls)
            {
                var conflict = false;
                var desc = _context.DataContext.WidgetDescriptors.Find(tmpl.ID);
                if (desc != null)
                {
                    var tversion = string.IsNullOrEmpty(tmpl.Version) ? "" : tmpl.Version;
                    var dversion = string.IsNullOrEmpty(desc.Version) ? "" : desc.Version;

                    if (string.IsNullOrEmpty(tversion) || string.IsNullOrEmpty(dversion) || (!tversion.ToLower().Equals(dversion.ToLower())))
                        conflict = true;

                    if ((tmpl.Modified - desc.Modified).Seconds != 0)
                        conflict = true;

                    if (conflict)
                    {
                        conflictCount++;
                    }
                }
            }
            ViewBag.Conflicts = conflictCount;
            #endregion

            var total = 0;
            var model = _context.DataContext.WidgetTemplates.WithIn(category, out total, query.Index - 1, query.Size).ToList();
            return View(new ModelWrapper()
            {
                Total = total,
                Model = model
            });
        }

        [Authorize]
        public ActionResult WidgetDesigner(Guid wid, string section)
        {
            if (_context.IsAuthorized<WidgetController>("Apply"))
            {
                ViewData["Element"] = "#" + wid.ToString();
                ViewData["WID"] = wid.ToString();
                ViewData["Prefix"] = wid.ToString().Substring(0, 5);
                ViewData["Section"] = "";

                if (!string.IsNullOrEmpty(section))
                {
                    ViewData["Element"] = "#" + wid.ToString() + ">" + section;
                    ViewData["Section"] = section;
                }

                var imgFolder = "~/webshared/home/images/";
                if (string.IsNullOrEmpty(section))
                {
                    imgFolder += "backgrounds";
                }
                else
                {
                    if (section.Equals(".d-widget-header"))
                        imgFolder += "headers";
                    if (section.Equals(".d-widget-body"))
                        imgFolder += "textures";

                }
                ViewData["ImagePath"] = Url.Content(imgFolder);
                return PartialView();
            }
            else
                return new HttpUnauthorizedResult();
            //return RedirectToAction("AccessDenied", "Security", new { Area = "" });
        }

        [Authorize]
        public void ApplyStyle(Guid wid, string section)
        {
            if (_context.IsAuthorized<WidgetController>("Apply"))
            {
                var widget = _context.DataContext.Widgets.Find(wid);// Service.GetWidget(wid);
                var csstext = ValueProvider.GetValue("CssText" + wid.ToString().Substring(0, 5)).AttemptedValue;

                if (string.IsNullOrEmpty(section))
                {
                    widget.CssText = csstext;
                }
                else
                {
                    if (section.Equals(".d-widget-header", StringComparison.OrdinalIgnoreCase))
                    {
                        widget.HeaderCssText = csstext;
                    }
                    else
                    {
                        widget.BodyCssText = csstext;
                    }
                }
                _context.DataContext.Widgets.Update(widget);
                _context.DataContext.SaveChanges(false);
                //widget.Update();
            }
        }

        public ActionResult GetPaths(string name)
        {
            string root = HttpContext.Server.MapPath(DESCRIPTOR_PATH);
            string fullPath = root + name;
            return Json(GetPathNodes(fullPath, root), JsonRequestBehavior.AllowGet);
        }

        [Authorize]
        public void Detect()
        {
            if (_context.IsAuthorized<WidgetController>("WidgetManager"))
            {
                string areaPath = HttpContext.Server.MapPath("~/Areas");
                string targetPath = HttpContext.Server.MapPath("~/bin");

                WidgetFounder.Detect(targetPath, _context.ApplicationPath, areaPath,
                   Membership.GetUser(User.Identity.Name),
                   _context.DataContext.WidgetDescriptors,
                   _context.DataContext.WidgetTemplates);
            }
        }

        private const string DESCRIPTOR_PATH = "~/content/widgets/";

        [Authorize, HttpPost]
        public ActionResult ResolveConflict()
        {
            if (_context.IsAuthorized<WidgetController>("WidgetManager"))
            {
                var tmpls = _context.DataContext.WidgetTemplates.All();
                var conflictCount = 0;
                foreach (var tmpl in tmpls)
                {
                    var conflict = false;
                    var desc = _context.DataContext.WidgetDescriptors.Find(tmpl.ID);
                    if (desc != null)
                    {
                        var tversion = string.IsNullOrEmpty(tmpl.Version) ? "" : tmpl.Version;
                        var dversion = string.IsNullOrEmpty(desc.Version) ? "" : desc.Version;

                        if (string.IsNullOrEmpty(tversion) || string.IsNullOrEmpty(dversion) || (!tversion.ToLower().Equals(dversion.ToLower())))
                            conflict = true;

                        if ((tmpl.Modified - desc.Modified).Seconds != 0)
                            conflict = true;

                        if (conflict)
                        {
                            conflictCount++;
                            _context.DataContext.WidgetDescriptors.Update(tmpl, desc);

                        }
                    }
                }

                if (conflictCount > 0)
                    _context.DataContext.SaveChanges(false);
            }
            return RedirectToAction("WidgetManager", new { Area = "" });
        }

        //public ActionResult ListWidgets(string name)
        //{
        //    string root = HttpContext.Server.MapPath(DESCRIPTOR_PATH);
        //    string fullPath = root + name;
        //    var dirInfo = new DirectoryInfo(fullPath);
        //    var dirs = dirInfo.GetDirectories();
        //    var widgets = new List<WidgetTemplate>();

        //    foreach (var dir in dirs)
        //    {
        //        var files = dir.GetFiles("config.xml");
        //        if (files.Length > 0)
        //        {
        //            var tmpl = XmlSerializerUtility.DeserializeFormXmlFile<WidgetTemplate>(files[0].FullName);
        //            widgets.Add(tmpl);
        //        }
        //    }
        //    ViewData["Path"] = name;
        //    return PartialView(widgets);
        //}

        /// <summary>
        /// Pack the widget runtime file , config file and resource files in a widget package for DotNetAge
        /// </summary>
        /// <param name="path"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public ActionResult PackWidget(string wid)
        {
            var packer = new Packer(HttpContext);
            var stream = new MemoryStream();
            var tmp = WebSiteContext.GetTemporaryDirectory(HttpContext);
            var id = Server.UrlDecode(wid);
            var tmpl = _context.DataContext.WidgetTemplates.Find(id);
            var widgetPath = HttpContext.Server.MapPath("~/content/widgets/") + id;
            
            if (!Directory.Exists(tmp))
                Directory.CreateDirectory(tmp);

            var pkg = new Package()
            {
                Name = tmpl.Name,
                Version = tmpl.Version,
                Description = tmpl.Description,
                Title =string.IsNullOrEmpty(tmpl.Defaults.Title) ? tmpl.Name: tmpl.Defaults.Title
            };
            
            //if (!string.IsNullOrEmpty(tmpl.Defaults.IconUrl))

            if (tmpl.Icons.Count > 0)
            {
                var _iconset = false;
                foreach (var ico in tmpl.Icons)
                {
                    var _icon = new ImageRes() { Height = ico.Height, Width = ico.Width, Url = widgetPath + "\\" + ico.Source };
                    
                    if (!_iconset && ico.Width >= 32)
                        _icon.IsDefault = true;
                    
                    pkg.Images.Add(_icon);
                }
            }

            if (tmpl.Licenses.Count > 0)
                tmpl.Licenses.AsParallel().ForAll(l => pkg.Licenses.Add(new Res() { Title = l.Text, Url = l.Source }));

            pkg.Authors.Add(new Contact()
            {
                Name = tmpl.Author.Name,
                Email = tmpl.Author.Email,
                WebSite = tmpl.Author.Uri
            });

            packer.Zip(stream, tmp, id, pkg);

            stream.Position = 0;
            Directory.Delete(tmp, true);

            return File(stream, "application/x-zip-compressed", pkg.Name + ".zip");

            #region Not use
            //if (_context.IsAuthorized<WidgetController>("WidgetManager"))
            //{
            //string root = DESCRIPTOR_PATH;
            //var id = Server.UrlDecode(wid);
            //string pkgPath = Server.MapPath(root) + id;
            //string rootPath = (new DirectoryInfo(pkgPath)).Parent.FullName;
            //var tmpl = _context.DataContext.WidgetTemplates.Find(id);

            //try
            //{
            //    var zip = new ZipCompress();
            //    zip.Path = pkgPath;
            //    RecursiveAddPaths(zip, pkgPath);
            //    var stream = zip.Compress();
            //    stream.Position = 0;
            //    //1.Add stream to another compressed stream 
            //    //3.Add manifest.xml to compress stream
            //    //4.Add install.xml to compress stream

            //    return File(stream, "application/x-zip-compressed", tmpl.Name + ".zip");
            //}
            //catch (Exception e)
            //{
            //    return File(e.Message, "text/plain", "error.txt");
            //}

            //}
            //else
            //    return RedirectToAction("AccessDenied", "Security", new { Area = "" }); 
            #endregion
        }

        //private void RecursiveAddPaths(ZipCompress zip, string path)
        //{
        //    var dirs = Directory.GetDirectories(path);
        //    for (int i = 0; i < dirs.Length; i++)
        //    {
        //        //var dir = new DirectoryInfo(dirs[i]);
        //        //zip.AddFile(dir.FullName, dir.FullName);
        //        RecursiveAddPaths(zip, dirs[i]);
        //    }

        //    var files = Directory.GetFiles(path);
        //    for (int i = 0; i < files.Length; i++)
        //    {
        //        var file = new FileInfo(files[i]);
        //        zip.AddFile(file.FullName, file.FullName);
        //    }
        //}

        [Authorize]
        public bool Unregister(string wid)
        {
            var id = Server.UrlDecode(wid);
            //throw new NotImplementedException();
            //if (_context.IsAuthorized<WidgetController>("WidgetManager"))
            //{
            //var tmpl = _context.DataContext.WidgetTemplates.Find(id);
            if (_context.DataContext.WidgetDescriptors.Find(id) != null)
                _context.DataContext.WidgetDescriptors.Delete(id);
            //_context.DataContext.WidgetTemplates.Delete(id);
            _context.DataContext.SaveChanges();
            return true;
            //}
            //return false;
        }

        [Authorize]
        public bool DeletePackage(string wid)
        {
            if (string.IsNullOrEmpty(wid))
                throw new ArgumentNullException("wid");
            try
            {
                var id = Server.UrlDecode(wid);
                _context.DataContext.WidgetTemplates.Delete(id);
            }
            catch
            {
                return false;
            }

            //if (_context.IsAuthorized<WidgetController>("WidgetManager"))
            //{
            //    var dir = Server.MapPath("~/content/widgets/" + path + "/" + name);
            //    if (System.IO.Directory.Exists(dir))
            //    {
            //        try
            //        {
            //            Directory.Delete(dir, true);
            //        }
            //        catch (Exception e)
            //        {
            //            return false;
            //        }
            //    }
            //    return true;
            //}
            return true;
        }

        [Authorize]
        public bool Register(string wid)
        {
            if (string.IsNullOrEmpty(wid))
                throw new ArgumentNullException("wid");

            var id = Server.UrlDecode(wid);
            var tmpl = _context.DataContext.WidgetTemplates.Find(id);
            _context.DataContext.WidgetDescriptors.Create(tmpl, tmpl.ID);
            return _context.DataContext.SaveChanges() > 0;
            //throw new NotImplementedException();
            //if (_context.IsAuthorized<WidgetController>("WidgetManager"))
            //{
            //    var tmpl = GetWidgetTemplate(path, name);
            //    this.CurrentWeb().AddWidgetDescriptor(tmpl, path + "\\" + name);
            //    return true;
            //}
        }

        //[Authorize]
        //public ActionResult ExtractWidget(string wid, string target)
        //{
        //    throw new NotImplementedException();
        //    //if (_context.IsAuthorized<WidgetController>("WidgetManager"))
        //    //{
        //    //    if (!string.IsNullOrEmpty(target) && !string.IsNullOrEmpty(id))
        //    //    {
        //    //        string tmpPath = Server.MapPath("~/shared/packages/tmp/" + id);
        //    //        var zip = new ZipExtract(tmpPath);
        //    //        string configText = zip.ReadFileAsText("config.xml");
        //    //        var tmpl = (WidgetTemplate)DNA.Utility.XmlSerializerUtility.DeserializeFromXmlText(configText, typeof(WidgetTemplate));
        //    //        var targetPath = Server.MapPath("~/content/widgets/" + target + "/" + tmpl.Name + "/");
        //    //        if (!System.IO.Directory.Exists(targetPath))
        //    //            System.IO.Directory.CreateDirectory(targetPath);
        //    //        zip.ExtractTo(targetPath);
        //    //        zip.Dispose();
        //    //        System.IO.File.Delete(tmpPath);
        //    //        return Content("Install completed");
        //    //    }
        //    //    return Content("Widget install fail!");
        //    //}
        //    //else return RedirectToAction("AccessDenied", "Security", new { Area = "" });
        //}

        //[Authorize]
        //public ActionResult PackageDetail(string wid, string target)
        //{
        //    throw new NotImplementedException();
        //    //string tmpPath = Server.MapPath("~/shared/packages/tmp/" + id);
        //    //ViewBag.ID = id;
        //    //var zip = new ZipExtract(tmpPath);
        //    //string configText = zip.ReadFileAsText("config.xml");
        //    //var tmpl = (WidgetTemplate)DNA.Utility.XmlSerializerUtility.DeserializeFromXmlText(configText, typeof(WidgetTemplate));
        //    //ViewBag.CanInstall = true;
        //    //ViewBag.Message = "";
        //    //ViewBag.Files = zip.ReadFiles();
        //    //ViewBag.Target = target;
        //    //var _descriptor = Service.GetWidgetDescriptor(target + "\\" + tmpl.Defaults.Action);
        //    //if (_descriptor != null)
        //    //{
        //    //    var usingCount = _descriptor.GetTemplate().GetInusingCount(target);
        //    //    if (usingCount > 0)
        //    //    {
        //    //        ViewBag.CanInstall = false;
        //    //        ViewBag.Message = string.Format(Resources.language.WidgetController_WidgetIsInstalled, usingCount.ToString());
        //    //    }
        //    //}
        //    //zip.Dispose();
        //    //return PartialView(tmpl);
        //}

        //[Authorize]
        //public ActionResult UploadWidget()
        //{
        //    HttpPostedFileBase file = null;
        //    if (Request.Files.Count > 0)
        //    {
        //        file = Request.Files[0];
        //        string tmpPath = Server.MapPath("~/shared/packages/tmp");

        //        if (file != null)
        //        {
        //            if (!System.IO.Directory.Exists(tmpPath))
        //                System.IO.Directory.CreateDirectory(tmpPath);
        //            string fileName = DateTime.Now.Ticks.ToString() + System.IO.Path.GetExtension(file.FileName);
        //            file.SaveAs(tmpPath + "\\" + fileName);
        //            return Content(fileName);
        //        }
        //    }
        //    return Content("");
        //}

        //[Authorize]
        //public ActionResult Detail(string path, string name)
        //{
        //    ViewData["Path"] = path;
        //    return PartialView(GetWidgetTemplate(path, name));
        //}

        [SecurityAction("Widgets", "Edit widget source", "Allows uses could edit the widget source file.",
    ThrowOnDeny = true,
    TitleResName = "SA_EditWidgetSrc",
    DescResName = "SA_EditWidgetSrcDesc",
    PermssionSetResName = "SA_Widgets"
    )]
        public ActionResult EditWidget(string wid)
        {
            string root = HttpContext.Server.MapPath(DESCRIPTOR_PATH);
            ViewBag.Categories = GetPathNodes(root, root);
            var tmpl = _context.DataContext.WidgetTemplates.Find(Server.UrlDecode(wid));

            // GetWidgetTemplate(path, name);

            if (string.IsNullOrEmpty(tmpl.Content.ContentType))
            {
                if (!string.IsNullOrEmpty(tmpl.Content.Source))
                {
                    string ext = Path.GetExtension(tmpl.Content.Source);
                    if (ext == ".ascx") tmpl.Content.ContentType = "ASP.NET FORM";
                    if (ext == ".cshtml") tmpl.Content.ContentType = "Razor(C#)";
                    if (ext == ".vbhtml") tmpl.Content.ContentType = "Razor(VB)";
                    string srcFile = Server.MapPath(DESCRIPTOR_PATH + tmpl.ID + "/" + tmpl.Content.Source);
                    //Server.MapPath(DESCRIPTOR_PATH + path + "/" + name + "/" + tmpl.Content.Source);
                    if (System.IO.File.Exists(srcFile))
                    {
                        using (var reader = System.IO.File.OpenText(srcFile))
                        {
                            tmpl.Content.Text = reader.ReadToEnd();
                        }
                    }
                }
            }
            else
            {
                tmpl.Content.ContentType = "Html";
            }
            return View(tmpl);
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult EditWidget(string wid, string contentHtml)
        {
            //var tmpl = GetWidgetTemplate(path, name);
            var tmpl = _context.DataContext.WidgetTemplates.Find(Server.UrlDecode(wid));

            if (!string.IsNullOrEmpty(tmpl.Content.ContentType) && tmpl.Content.ContentType.Equals("text/html", StringComparison.OrdinalIgnoreCase))
            {
                tmpl.Content.Text = contentHtml;
                _context.DataContext.WidgetTemplates.Update(tmpl);
                //                string widgetPath = HttpContext.Server.MapPath(DESCRIPTOR_PATH + tmpl.ID) + "\\";
                //                DNA.Utility.XmlSerializerUtility.SerializeToXmlFile(widgetPath + "config.xml", typeof(WidgetTemplate), tmpl);
            }
            else
            {
                string file = Server.MapPath(DESCRIPTOR_PATH + tmpl.ID + "/" + tmpl.Content.Source);
                System.IO.File.WriteAllText(file, contentHtml);
                //using (var writer = new StreamWriter(System.IO.File.OpenWrite(file)))
                //{
                //    writer.Write(contentHtml);
                //}
            }

            return RedirectToAction("EditWidget", new { wid = wid });
        }

        [SecurityAction("Widgets", "Create widget", "Allows uses write widgets by using widget editor.",
    ThrowOnDeny = true, TitleResName = "SA_CreateWidget", DescResName = "SA_CreateWidgetDesc",
    PermssionSetResName = "SA_Widgets")]
        [SiteControlPanel(ResKey = "RES_CREATE", Group = "Widgets", Order = 2, GroupResKey = "RES_WIDGETS", ShowInTopSiteOnly = true)]
        [HttpGet]
        public ActionResult CreateWidget()
        {
            //string root = HttpContext.Server.MapPath(DESCRIPTOR_PATH);
            ViewBag.Categories = _context.DataContext.WidgetTemplates.GetCategories();
            // GetPathNodes(root, root);
            return View();
        }
        [SecurityAction("Widgets", "Create widget", "Allows uses write widgets by using widget editor.",
    ThrowOnDeny = true, TitleResName = "SA_CreateWidget", DescResName = "SA_CreateWidgetDesc",
    PermssionSetResName = "SA_Widgets")]

        [HttpPost]
        public ActionResult CreateWidget(SimpleWidgetModel widget)
        {
            ViewBag.Categories = _context.DataContext.WidgetTemplates.GetCategories();
            
            if (ModelState.IsValid)
            {

                var user = System.Web.Security.Membership.GetUser(User.Identity.Name);
                string root = HttpContext.Server.MapPath(DESCRIPTOR_PATH + widget.Category);
                string _id = widget.Category + "\\" + widget.Name;
                string widgetPath = root + "\\" + widget.Name + "\\";

                if (Request.Files.Count > 0)
                {
                    for (int i = 0; i < Request.Files.Count; i++)
                    {
                        if (Request.Files[i].ContentLength > 0)
                        {
                            if (!Request.Files[i].ContentType.Equals("image/png", StringComparison.OrdinalIgnoreCase) && !Request.Files[i].ContentType.Equals("image/gif", StringComparison.OrdinalIgnoreCase))
                            {
                                ViewData.ModelState.AddModelError("", Resources.language.WidgetController_ImageTypesAllow);
                                return View(widget);
                            }
                        }
                    }
                }

                if (!System.IO.Directory.Exists(root))
                    System.IO.Directory.CreateDirectory(root);

                if (!System.IO.Directory.Exists(widgetPath))
                    System.IO.Directory.CreateDirectory(widgetPath);
                else
                {
                    ViewData.ModelState.AddModelError("", Resources.language.WidgetController_WidgetNameExists);
                    return View(widget);
                }

                var tmpl = new WidgetTemplate()
                {
                    Name = widget.Name,
                    ID = _id,
                    Version = "1.0",
                    Author = new WidgetAuthor()
                    {
                        Name = user.GetProfile()["DisplayName"].ToString(),
                        Email = user.Email,
                        Uri = user.GetPermalinkUrl().ToString()
                    },
                    Defaults = new WidgetDefaults()
                    {
                        Title = widget.Title
                    },
                    Description = widget.Description
                };

                if (widget.ContentType.Equals("html"))
                {
                    tmpl.Content.ContentType = "text/html";
                }
                else
                {
                    tmpl.Content.Source = "index." + widget.ContentType;
                    System.IO.File.Copy(Server.MapPath("~/content/templates/index." + widget.ContentType), widgetPath + "index." + widget.ContentType);
                }

                if (Request.Files.Count > 0)
                {
                    tmpl.Icons = new List<WidgetIcon>();
                    Directory.CreateDirectory(widgetPath + "images");

                    if (Request.Files["WidgetIconFile"].ContentLength > 0)
                    {
                        var ico = Request.Files["WidgetIconFile"];

                        var icoFile = Path.GetFileName(ico.FileName);
                        ico.SaveAs(widgetPath + "images\\" + icoFile);
                        tmpl.Icons.Add(new WidgetIcon()
                        {
                            Width = 16,
                            Height = 16,
                            Source = "images/" + icoFile
                        });
                    }

                    if (Request.Files["Widget_Image"].ContentLength > 0)
                    {
                        var imgFile = Path.GetFileName(Request.Files["Widget_Image"].FileName);
                        Request.Files["Widget_Image"].SaveAs(widgetPath + "images\\" + imgFile);
                        tmpl.Icons.Add(new WidgetIcon()
                        {
                            Width = 48,
                            Height = 48,
                            Source = "images/" + imgFile
                        });
                    }
                }
                _context.DataContext.WidgetTemplates.Create(tmpl);

                //DNA.Utility.XmlSerializerUtility.SerializeToXmlFile(widgetPath + "config.xml", typeof(WidgetTemplate), tmpl);
                return RedirectToAction("EditWidget", new { wid = _id });
            }
            return View(widget);
        }

        [Authorize]
        public bool AddParam(string wid, string paramName, string paramType, string defaultValue)
        {
            // throw new NotImplementedException();
            //if (_context.IsAuthorized<WidgetController>("CreateWidget") || _context.IsAuthorized<WidgetController>("EditWidget"))
            //{
            var id = Server.UrlDecode(wid);
            var tmpl = _context.DataContext.WidgetTemplates.Find(id);
            //GetWidgetTemplate(path, name);

            //if (!string.IsNullOrEmpty(tmpl.Content.ContentType) && tmpl.Content.ContentType.Equals("text/html", StringComparison.OrdinalIgnoreCase))
            //{
            if (tmpl.UserPreferences == null)
                tmpl.UserPreferences = new List<WidgetUserPreference>();

            if (tmpl.UserPreferences.Count > 0)
            {
                if (tmpl.UserPreferences.Exists(p => p.Name.Equals(paramName, StringComparison.OrdinalIgnoreCase)))
                    return false;
            }

            tmpl.UserPreferences.Add(new WidgetUserPreference()
            {
                Name = paramName,
                Type = paramType,
                Value = defaultValue
            });

            var descriptor = _context.DataContext.WidgetDescriptors.Find(id);
            // Service.GetWidgetDescriptor(path + "\\" + name);

            if (descriptor != null)
            {
                var properties = descriptor.Properties;
                properties.Add(paramName, Convert.ChangeType(defaultValue, Type.GetType(paramType)));
                descriptor.Properties = properties;
                _context.DataContext.WidgetDescriptors.Update(descriptor);
                _context.DataContext.SaveChanges();
                //Service.UpdateWidgetDescriptor(descriptor);
            }
            _context.DataContext.WidgetTemplates.Update(tmpl);
            //string widgetPath = HttpContext.Server.MapPath(DESCRIPTOR_PATH + path) + "\\" + tmpl.Name + "\\";
            //DNA.Utility.XmlSerializerUtility.SerializeToXmlFile(widgetPath + "config.xml", typeof(WidgetTemplate), tmpl);
            //}
            return true;
            // }
            //else
            //   return false;
        }

        [Authorize]
        public bool DeleteParam(string wid, string paramName)
        {
            var id = Server.UrlDecode(wid);

            var tmpl = _context.DataContext.WidgetTemplates.Find(id);

            //if (!string.IsNullOrEmpty(tmpl.Content.ContentType) && tmpl.Content.ContentType.Equals("text/html", StringComparison.OrdinalIgnoreCase))
            //{
                if (tmpl.UserPreferences == null)
                    tmpl.UserPreferences = new List<WidgetUserPreference>();

                if (tmpl.UserPreferences.Count > 0)
                {
                    if (tmpl.UserPreferences.Exists(p => p.Name.Equals(paramName, StringComparison.OrdinalIgnoreCase)))
                    {
                        tmpl.UserPreferences.Remove(tmpl.UserPreferences.Find(p => p.Name.Equals(paramName, StringComparison.OrdinalIgnoreCase)));
                        var descriptor = _context.DataContext.WidgetDescriptors.Find(id);
                        if (descriptor != null)
                        {
                            var properties = descriptor.Properties;
                            properties.Remove(paramName);
                            descriptor.Properties = properties;
                            _context.DataContext.WidgetDescriptors.Update(descriptor);
                            _context.DataContext.SaveChanges();
                        }
                        _context.DataContext.WidgetTemplates.Update(tmpl);
                    }
                }
//}
            return false;
        }
    }
}
